﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO.Compression;


namespace SampleArchiver
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
            {
                Console.Error.WriteLine(e.ExceptionObject);
                Environment.Exit(1);
            };

            if (args.Length != 3)
            {
                Console.Error.WriteLine("Error argument.");
                Environment.Exit(2);
            }

            Task t = null;

            if (args[0] == "-c")
            {
                t = Compress(args[1], args[2]);
            }
            else if (args[0] == "-e")
            {
                t = Expand(args[1], args[2]);
            }
            else
            {
                Console.Error.WriteLine("Error argument.");
                Environment.Exit(2);
            }

            t.Wait();
        }

        private async static Task Compress(string inputDirectory, string outputFile)
        {
            if (!Directory.Exists(inputDirectory))
            {
                Console.Error.WriteLine("Input directory does not exits.");
                Environment.Exit(2);
            }

            var outDic = Path.GetDirectoryName(outputFile);

            if (string.IsNullOrEmpty(outDic))
            {
                Console.Error.WriteLine("Directory of output path does not exits.");
                Environment.Exit(2);
            }

            if (!Directory.Exists(outDic))
            {
                Console.Error.WriteLine("Directory of output path does not exits.");
                Environment.Exit(2);
            }

            Console.WriteLine("Start compress...");

            var progress = new ConsoleProgress<FileSystemProgressInfo>();

            int i = 0;
            progress.ProgressChanged += (sender, e) =>
            {
                i++;
                Console.WriteLine("Added : " + e.FileSystemInfo.Name + string.Format(" ({0}/{1}).", i, e.All.Count));
            };

            await ZipFileEx.CreateFromDirectoryAsync(inputDirectory, outputFile, CompressionLevel.Optimal, false, Encoding.Default, progress);

            Console.WriteLine("finished.");
        }

        private async static Task Expand(string inputFile, string outputDirectory)
        {
            if (!File.Exists(inputFile))
            {
                Console.Error.WriteLine("Input archive file does not exits.");
                Environment.Exit(2);
            }

            if (!Directory.Exists(outputDirectory))
            {
                Console.Error.WriteLine("Output directory does not exits.");
                Environment.Exit(2);
            }

            try
            {
                var check = ZipFile.OpenRead(inputFile);
            }
            catch
            {
                Console.Error.WriteLine("Input archive file is wrong");
                Environment.Exit(2);
            }

            Console.WriteLine("Start expand...");

            var progress = new ConsoleProgress<ZipArchiveEntryProgressInfo>();

            int i = 0;
            progress.ProgressChanged += (sender, e) =>
            {
                i++;
                Console.WriteLine("Expanded : " + e.ZipArchiveEntry.Name + string.Format(" ({0}/{1}).", i, e.All.Count));
            };

            await ZipFileEx.ExtractToDirectoryAsync(inputFile, outputDirectory, Encoding.Default, progress);

            Console.WriteLine("finished");
        }
    }

    public class ConsoleProgress<T> : IProgress<T>
    {
        public void Report(T value)
        {
            RaiseProgressChanged(value);
        }

        public event EventHandler<T> ProgressChanged;

        protected virtual void RaiseProgressChanged(T arg)
        {
            var handler = ProgressChanged;

            if (handler != null)
            {
                handler(this, arg);
            }
        }
    }
}
